package com.demo.spi;

import java.util.ServiceLoader;

/**
 * Java 的 SPI（Service Provider Interface）机制默认读取 META-INF/services/ 路径下的文件。 <br/>
 * 项目根目录/
 * └── META-INF/
 *     └── services/
 *         └── 接口全限定名文件
 *
 */
public class SPITest {

    // 1. 如果你的接口是 com.example.DatabaseDriver，那么配置文件的完整路径应该是：src/main/resources/META-INF/services/com.example.DatabaseDriver
    // 或者打包后在 JAR 中的位置：                                                                META-INF/services/com.example.DatabaseDriver

    // 2. 文件内容格式
    // 文件内容包含实现类的全限定名，每行一个：
    // com.demo.spi.MysqlDriver
    // com.demo.spi.PostgresDriver


    /**
     * 这个是java的SPI机制的测试类，和SpringBoot的SPI机制不一样，SpringBoot的SPI机制是通过SpringFactoriesLoader来加载的，路径（Spring Boot: META-INF/spring.factories）
     * @param args
     */
    public static void main(String[] args) {

        /**
         * 问😚：这个java的SPI我是不是可以简单理解为根据META-INF/services/里的配置给我new出来了DatabaseDriver的所有配置的接口示例，相当于手动new MysqlDriver()和new PostgresDriver()对不对？
         *
         * 答：可以这样简单理解。Java 的 SPI 机制通过 ServiceLoader 类来动态加载和实例化实现了指定接口的类。它会读取 META-INF/services/ 目录下对应接口的配置文件，然后根据文件中列出的实现类全限定名，使用反射机制创建这些类的实例。
         * Java SPI 机制会根据 META-INF/services/ 目录下的配置文件，自动帮你实例化（new）所有实现了指定接口（如 DatabaseDriver）的类，相当于你手动 new MysqlDriver() 和 new PostgresDriver()，但它是通过反射和配置文件自动完成的，无需你在代码里写死具体实现类。
         */
        ServiceLoader<DatabaseDriver> drivers = ServiceLoader.load(DatabaseDriver.class);

        for (DatabaseDriver driver : drivers) {
            driver.connect();
            driver.executeQuery("SELECT * FROM users");
        }
    }
}
